package spring.boot.btc.service;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import spring.boot.btc.common.BlockProperty;
import spring.boot.btc.model.Block;
import spring.boot.btc.model.TransactionInput;
import spring.boot.btc.model.TransactionOutput;
import spring.boot.btc.model.Wallet;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class WalletService {

    @Autowired
    private BlockSenderService blockSenderService;


    /**
     * 获取用户钱包余额
     */
    public long getBalance() {
        List<Block> blockList = BlockProperty.blockList;

        long inputMoney = 0;
        long outputMoney = 0;

        for (Block block : blockList) {
            List<TransactionInput> inputList = block.getTransaction().getTransactionInputList();
            for (TransactionInput input : inputList) {
                if (input.getAddress() != null && Wallet.getInstance().getAddress().equals(input.getAddress())) {
                    inputMoney = inputMoney + input.getMoney();
                }
            }
            List<TransactionOutput> outputList = block.getTransaction().getTransactionOutputList();
            for (TransactionOutput output : outputList) {
                if (output.getAddress() != null && Wallet.getInstance().getAddress().equals(output.getAddress())) {
                    outputMoney = outputMoney + output.getMoney();
                }
            }
        }

        return outputMoney - inputMoney;
    }

    /**
     * 自己给他人转账
     *
     * @param account 目标账户
     */
    public long trans(String account, long money) {
        long balance = getBalance();
        if (balance < money) {
            log.info("余额小于转账目标金额，余额不足！");
            return -1;
        }
        if (account.equals(Wallet.getInstance().getAddress())) {
            log.info("自己不能给自己转账！");
            return -2;
        }
        List<Block> blockList = BlockProperty.blockList;
        Map<String, Block> inputMap = new HashMap<>();
        Map<String, Block> outputMap = new HashMap<>();

        //总结区块中与自己有关的所有的输入和输出
        for (Block block : blockList) {
            List<TransactionInput> inputList = block.getTransaction().getTransactionInputList();
            for (TransactionInput input : inputList) {
                if (Wallet.getInstance().getAddress().equals(input.getAddress())) {
                    inputMap.put(block.getHash(), block);
                }
            }
            List<TransactionOutput> outputList = block.getTransaction().getTransactionOutputList();
            for (TransactionOutput output : outputList) {
                if (Wallet.getInstance().getAddress().equals(output.getAddress())) {
                    outputMap.put(block.getHash(), block);
                }
            }
        }

        //把所有已经花费的输出剔除
        for (Map.Entry<String, Block> blockMap : outputMap.entrySet()) {
            if (inputMap.containsKey(blockMap.getKey())) {
                outputMap.remove(blockMap.getKey());
            }
        }

        long myMoney = 0;
        final List<TransactionInput> inputs = new ArrayList<>();
        List<TransactionOutput> outputs = new ArrayList<>();

        for (Map.Entry<String, Block> blockMap : outputMap.entrySet()) {
            List<TransactionOutput> outputList = blockMap.getValue().getTransaction().getTransactionOutputList();
            for (int i = 0; i < outputList.size(); i++) {
                if (outputList.get(i).getAddress().equals(Wallet.getInstance().getAddress())) {
                    myMoney = myMoney + outputList.get(i).getMoney();
                    TransactionInput input = new TransactionInput(outputList.get(i).getPublicKey(), outputList.get(i).getMoney(), blockMap.getKey(), i);
                    inputs.add(input);
                }
            }
            if (myMoney >= money) {
                break;
            }
        }

        if (myMoney > money) {
            TransactionOutput output = new TransactionOutput(Wallet.getInstance().getPublicKeyString(), myMoney - money);
            outputs.add(output);
        }


        Map map = new HashMap(8);
        map.put("inputs", inputs);
        map.put("outputs", outputs);
        map.put("address", account);
        map.put("money", money);

        Map transMap = new HashMap(4);
        transMap.put("type", 2);
        transMap.put("msg", map);

        blockSenderService.send(JSON.toJSONString(transMap));
        return 0;
    }
}
